package com.supreme.cacheserver.service;

import com.supreme.cacheserver.annotation.RedisLock;
import com.supreme.common.constant.ConsoleColors;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
@RedisLock(name = "redissonServiceClass")
public class RedissonService {

    @Resource
    private RedissonClient redissonClient;

    public void testRedissonLock(String lockKey) {
        RLock redissonLock = redissonClient.getLock(lockKey);
        redissonLock.lock();
        String threadName = Thread.currentThread().getName();
        ConsoleColors.printf(ConsoleColors.GREEN_BOLD_BRIGHT, "ThreadName = %s Key = %s Start", threadName, lockKey);

        try {
            TimeUnit.SECONDS.sleep(10);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        ConsoleColors.printf(ConsoleColors.RED_BOLD_BRIGHT, "ThreadName = %s Key = %s Finish", threadName, lockKey);
        redissonLock.unlock();
    }

    public void testRedissonTryLock(String lockKey) {
        RLock redissonLock = redissonClient.getLock(lockKey);
        boolean tryLock = redissonLock.tryLock();
        String threadName = Thread.currentThread().getName();

        if (tryLock) {
            ConsoleColors.printf(ConsoleColors.GREEN_BOLD_BRIGHT, "ThreadName = %s Key = %s Start", threadName, lockKey);
            try {
                TimeUnit.SECONDS.sleep(10);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        } else {
            ConsoleColors.printf(ConsoleColors.YELLOW_BOLD_BRIGHT, "ThreadName = %s Key = %s Fault", threadName, lockKey);
        }

        if (tryLock) {
            ConsoleColors.printf(ConsoleColors.RED_BOLD_BRIGHT, "ThreadName = %s Key = %s Finish", threadName, lockKey);
            redissonLock.unlock();
        }
    }

    public void testRedissonTryLockTimeout(String lockKey) {
        RLock redissonLock = redissonClient.getLock(lockKey);
        boolean tryLock;
        try {
            tryLock = redissonLock.tryLock(5, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        String threadName = Thread.currentThread().getName();

        if (tryLock) {
            ConsoleColors.printf(ConsoleColors.GREEN_BOLD_BRIGHT, "ThreadName = %s Key = %s Start", threadName, lockKey);
            try {
                TimeUnit.SECONDS.sleep(10);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        } else {
            ConsoleColors.printf(ConsoleColors.YELLOW_BOLD_BRIGHT, "ThreadName = %s Key = %s Fault", threadName, lockKey);
        }

        if (tryLock) {
            ConsoleColors.printf(ConsoleColors.RED_BOLD_BRIGHT, "ThreadName = %s Key = %s Finish", threadName, lockKey);
            redissonLock.unlock();
        }
    }

    public void lockCode(String code) {
        String lockKey = "CODE_" + code;
        String name = Thread.currentThread().getName();
        RLock lock = redissonClient.getLock(lockKey);
        lock.lock();
        try {
            log.info("LockCode Start = {}", name);
            TimeUnit.SECONDS.sleep(10);
            log.info("LockCode Finish = {}", name);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        lock.unlock();
    }

    public void testRedissonAnnoDummy(@RedisLock(name = "redissonServiceParam") String code) {

    }

    @RedisLock(keyPrefix = "SO", keySep = "_", tryLock = true, waitTime = 5)
    public int redisLockForCode(@RedisLock String code, Integer type, String name) {
        try {
            log.info("LockCode Start = {}", code);
            TimeUnit.SECONDS.sleep(10);
            log.info("LockCode Finish = {}", code);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        return 1;
    }

    @RedisLock(keyPrefix = "SO", keySep = "_", tryLock = false, lockKey = "fuck")
    public int redisLockForAnno(String code, Integer type, String name) {
        try {
            log.info("LockCode Start = {}", code);
            TimeUnit.SECONDS.sleep(10);
            log.info("LockCode Finish = {}", code);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        return 1;
    }
}
